////////////////////////////////////////////////////////////////////////////
//
//  CryEngine Source File.
//  Copyright (C), Crytek, 2010.
// -------------------------------------------------------------------------
//  File name:   CryGameSpyMatchMaking.h
//  Version:     v1.00
//  Created:     29/03/2010 by Paul Mikell.
//  Description: CCryGameSpyMatchMaking class definition
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////


#ifndef __CRYGAMESPYMATCHMAKING_H__

#define __CRYGAMESPYMATCHMAKING_H__


#if _MSC_VER > 1000
#pragma once
#endif


#include "Lobby/CryMatchMaking.h"
#include "Lobby/GameSpy/CryGameSpyLobby.h"
#include "CryLobbyPacket.h"

#include "StringUtils.h"

#if USE_CRYLOBBY_GAMESPY


#include "Gamespy2.11.00/Source/gp/gp.h"
#include "Gamespy2.11.00/Source/Peer/peer.h"
#include "Gamespy2.11.00/Source/natneg/natneg.h"

#define MAX_GAMESPY_SEARCH_SERVERS	32767
#define MAX_GAMESPY_SEARCHES				1

#define GAMESPY_MAX_TITLE_LEN							31	// title + nul termination must fit in PI_TITLE_MAX_LEN (32, not exposed by GameSpy SDK)
																																		 // title (max 31 characters)         ip              port  sid             nul
#define GAMESPY_MAX_SESSION_URL_SIZE			GAMESPY_MAX_TITLE_LEN + 42 // ThisIsTheTitleThisIsTheTitleThi://123.123.123.123:64100/DEADBEEFBAADF00D\0
#define GAMESPY_ENCODE_NUMERIC_TABLE_SIZE					84
#define GAMESPY_DECODE_NUMERIC_TABLE_SIZE					128

#define GAMESPY_SEARCH_FILTER_RESERVED_LEN		28	// Maximum number of characters for format "(groupid=%d) AND (%s)" excluding the %s.
#define GAMESPY_SEARCH_FILTER_AVAILABLE_LEN		( MAX_FILTER_LEN - GAMESPY_SEARCH_FILTER_RESERVED_LEN )

#define GAMESPY_CD_KEY_CHALLENGE_SIZE		33
#define GAMESPY_CD_KEY_RESPONSE_SIZE		73

#define GAMESPY_CD_KEY_LOCALID_CYCLE_MASK							0x007FFFFF
#define GAMESPY_CD_KEY_LOCALID_LOBBYCONNECTION_SHIFT	23
#define GAMESPY_CD_KEY_LOCALID_LOBBYCONNECTION_MASK		0x1F800000
#define GAMESPY_CD_KEY_LOCALID_SESSION_INDEX_SHIFT		29
#define GAMESPY_CD_KEY_LOCALID_SESSION_INDEX_MASK			0x60000000
#define GAMESPY_CD_KEY_LOCALID_SERVER									0x80000000

class CCryGameSpyLobbyService;

enum EGSNatState
{
	eGSNT_NotStarted,
	eGSNT_Started,
	eGSNT_Succeeded,
	eGSNT_Failed
};

struct SCryGameSpyRemoteConnectionID
{
	EGSNatState			m_state;
	uint32					m_cookie;
	uint32					m_useIP;
	uint32					m_privateIP;
	uint32					m_publicIP;
	uint16					m_usePort;
	uint16					m_privatePort;
	uint16					m_publicPort;
};

// If the size and/or layout of SCryGameSpySessionID changes, its
// GetSizeInPacket, WriteToPacket, and ReadFromPacket must be changed to reflect
// this. Most importantly, these functions must not include size of
// SCryGameSpySessionID's vtab pointer, serialize the vtab pointer into a
// packet, or deserialize the vtab pointer out of a packet.

struct SCryGameSpySessionID: public SCrySharedSessionID
{
	uint64												m_sid;
	SCryGameSpyRemoteConnectionID	m_addr;

	virtual bool operator==( const SCrySessionID&	other )
	{
		return ( m_sid == ( ( const SCryGameSpySessionID& )other ).m_sid );
	};
	virtual bool operator<( const SCrySessionID&	other )
	{
		return ( m_sid < ( ( const SCryGameSpySessionID& )other ).m_sid );
	};
	SCryGameSpySessionID&  operator=(const SCryGameSpySessionID &other)
	{
		m_sid = other.m_sid;
		m_addr = other.m_addr;
		return *this;
	}

	// m_addr.m_state, m_addr.m_cookie, m_addr.m_useIP, and m_addr.m_usePort are
	// intentionally omitted from these three functions; they're specific to the
	// pair of peers that completed the NAT negotiation to which they refer, and
	// will not be usable by the peer to which the packet will be sent.

	static uint32 GetSizeInPacket()
	{
		return sizeof ( uint64 ) + sizeof ( uint32 ) + sizeof ( uint32 ) + sizeof ( uint16 ) + sizeof ( uint16 );
	};

	void WriteToPacket( CCryLobbyPacket* pPacket ) const
	{
		pPacket->WriteUINT64( m_sid );
		pPacket->WriteUINT32( m_addr.m_privateIP );
		pPacket->WriteUINT32( m_addr.m_publicIP );
		pPacket->WriteUINT16( m_addr.m_privatePort );
		pPacket->WriteUINT16( m_addr.m_publicPort );
	};

	void ReadFromPacket( CCryLobbyPacket* pPacket )
	{
		m_sid = pPacket->ReadUINT64();
		m_addr.m_state = eGSNT_NotStarted;
		m_addr.m_cookie = 0;
		m_addr.m_useIP = 0;
		m_addr.m_privateIP = pPacket->ReadUINT32();
		m_addr.m_publicIP = pPacket->ReadUINT32();
		m_addr.m_usePort = 0;
		m_addr.m_privatePort = pPacket->ReadUINT16();
		m_addr.m_publicPort = pPacket->ReadUINT16();
	};
	bool IsFromInvite() const
	{
		return true;
	}

	void AsCStr( char* pOutString, int inBufferSize ) const
	{
		snprintf( pOutString, inBufferSize, "%lld", m_sid );
		pOutString[inBufferSize-1]=0;
	}
};


struct SCryGameSpyUserID: public SCrySharedUserID
{
	SCryGameSpyUserID() : m_profileID(0) {};
	SCryGameSpyUserID(GPProfile profileID) : m_profileID(profileID) {};

	virtual bool operator==( const SCryUserID& other ) const
	{
		return m_profileID == static_cast< const SCryGameSpyUserID& >( other ).m_profileID;
	};

	virtual bool operator<( const SCryUserID& other ) const
	{
		return m_profileID < static_cast< const SCryGameSpyUserID& >( other ).m_profileID;
	};

	virtual CryFixedStringT< CRYLOBBY_USER_GUID_STRING_LENGTH > GetGUIDAsString() const
	{
		CryFixedStringT< CRYLOBBY_USER_GUID_STRING_LENGTH >	result;

		result.Format( "%08X", m_profileID );

		return result;
	};

	SCryGameSpyUserID&  operator=(const SCryGameSpyUserID &other)
	{
		m_profileID = other.m_profileID;
		return *this;
	}

	GPProfile						m_profileID;
};


class CCryGameSpyMatchMaking : public CCryMatchMaking, public ICryGameSpyLobbyComponent
{
public:

	// Description:
	//	 Constructor for CCryGameSpyMatchMaking.
	// Arguments:
	//	 pLobby - lobby
	//	 pService - lobby service
	CCryGameSpyMatchMaking( CCryLobby* pLobby, CCryLobbyService* pService, ECryLobbyService serviceType );

	// Description:
	//	 Destructor for CCryGameSpyMatchMaking.
	virtual ~CCryGameSpyMatchMaking();

	// Description:
	//	 Initialise CCryGameSpyMatchMaking.
	ECryLobbyError Initialise();

	// Description:
	//	 Terminate CCryGameSpyMatchMaking.
	ECryLobbyError Terminate();

	// Description:
	//	 Tick the CCryGameSpyMatchMaking.
	// Arguments:
	//	 tv - time
	void Tick( CTimeValue tv );

	// Description:
	//	 Called when a packet is received.
	// Arguments:
	//	 addr - sender
	//	 pData - data
	//	 length - length
	void OnPacket( const TNetAddress& addr, CCryLobbyPacket* pPacket );


	//////////////////////////////////////////////////////////
	// ICryMatchMaking implementation
	//////////////////////////////////////////////////////////

	// Description:
	//	 This function must be called by all peers before any other matchmaking
	//	 calls. It defines the applications custom data used for it's sessions. This
	//	 data is advertised when a host creates a session and gets returned when a
	//	 session search is performed
	// Arguments:
	//	 pData - Pointer to an array of SCrySessionUserData that defines the applications custom data for a session
	//	 numData - Number of items in the data array
	//	 pTaskID - Pointer to buffer to store the task ID to identify this call in the callback
	//	 cb - Callback function that is called when function completes
	//	 pCbArg - Pointer to application-specified data that is passed to the callback
	// Return:
	//	 eCLE_Success if function successfully started or an error code if function failed to start
	virtual ECryLobbyError SessionRegisterUserData( SCrySessionUserData* pData, uint32 numData, CryLobbyTaskID* pTaskID, CryMatchmakingCallback cb, void* pCbArg );

	// Description:
	//	 Called by the host to create a session and make it available for others to join.
	// Arguments:
	//	 pUsers - Pointer to an array of local users who will be joining the session after creation. The first user will be the session owner
	//							The numbers given should be the pad numbers the users are using.
	//							It is important that these are correct on live as multiple accounts can be signed in one for each pad.
	//							If the wrong pad numbers are passed in then the wrong accounts will be used for the session.
	//							Remember even on a single account machine and single player game the user doesn't have to be using and signed in on pad 0
	//	 numUsers - Number of users in the users array
	//	 flags - Session create flags that control how the session behaves
	//	 pData - Pointer to a SCrySessionData that describes the session
	//	 pTaskID - Pointer to buffer to store the task ID to identify this call in the callback
	//	 cb - Callback function that is called when function completes
	//	 pCbArg - Pointer to application-specified data that is passed to the callback
	// Return:
	//	 eCLE_Success if function successfully started or an error code if function failed to start
	virtual ECryLobbyError SessionCreate( uint32* pUsers, int numUsers, uint32 flags, SCrySessionData* pData, CryLobbyTaskID* pTaskID, CryMatchmakingSessionCreateCallback cb, void* pCbArg );

	virtual ECryLobbyError SessionMigrate( CrySessionHandle h, uint32* pUsers, int numUsers, uint32 flags, SCrySessionData* pData, CryLobbyTaskID* pTaskID, CryMatchmakingSessionCreateCallback pCB, void* pCBArg );

	// Description:
	//	 Called by the host to update the applications custom data. Only the data
	//	 items that need updating need to be given.
	// Arguments:
	//	 gameSessionHandle - Handle to the session to be updated
	//	 pData - Pointer to an array of SCrySessionUserData that contains the applications custom data that will be updated for the session
	//	 numData - Number of items in the data array
	//	 pTaskID - Pointer to buffer to store the task ID to identify this call in the callback
	//	 cb - Callback function that is called when function completes
	//	 pCbArg - Pointer to application-specified data that is passed to the callback
	// Return:
	//	 eCLE_Success if function successfully started or an error code if function failed to start
	virtual ECryLobbyError SessionUpdate( CrySessionHandle h, SCrySessionUserData* pData, uint32 numData, CryLobbyTaskID* pTaskID, CryMatchmakingCallback	cb, void* pCbArg );
	virtual ECryLobbyError SessionUpdateSlots(CrySessionHandle h, uint32 numPublic, uint32 numPrivate, CryLobbyTaskID* pTaskID, CryMatchmakingCallback pCB, void* pCBArg);

	// Description:
	//	 Called by any one to retrieve the current state of the session.
	// Arguments:
	//	 h - Handle to the session to query
	//	 pTaskID - Pointer to buffer to store the task ID to identify this call in the callback
	//	 cb - Callback function that is called when function completes
	//	 pCbArg - Pointer to application-specified data that is passed to the callback
	// Return:
	//	 eCLE_Success if function successfully started or an error code if function failed to start
	virtual ECryLobbyError SessionQuery( CrySessionHandle h, CryLobbyTaskID* pTaskID, CryMatchmakingSessionQueryCallback pCB, void* pCBArg );

	// Description:
	//	 Called by any one to retrieve the list of users in the session.
	// Arguments:
	//	 h - Handle to the session to get user information from
	//	 pTaskID - Pointer to buffer to store the task ID to identify this call in the callback
	//	 cb - Callback function that is called when function completes
	//	 pCBArg - Pointer to application-specified data that is passed to the callback
	// Return:
	//	 eCLE_Success if function successfully started or an error code if function failed to start
	virtual ECryLobbyError SessionGetUsers( CrySessionHandle h, CryLobbyTaskID* pTaskID, CryMatchmakingSessionGetUsersCallback pCB, void* pCBArg );

	virtual ECryLobbyError SessionStart( CrySessionHandle h, CryLobbyTaskID* pTaskID, CryMatchmakingCallback	cb, void* pCbArg );

	virtual ECryLobbyError SessionEnd( CrySessionHandle h, CryLobbyTaskID* pTaskID, CryMatchmakingCallback	cb, void* pCbArg );

	// Description:
	//	 Called by all members of the session to delete it when they have finished with it.
	// Arguments:
	//	 localSessionIndex - Handle to the session to delete
	//	 pTaskID - Pointer to buffer to store the task ID to identify this call in the callback
	//	 cb - Callback function that is called when function completes
	//	 pCbArg - Pointer to application-specified data that is passed to the callback
	// Return:
	//	 eCLE_Success if function successfully started or an error code if function failed to start
	virtual ECryLobbyError SessionDelete( CrySessionHandle localSessionIndex, CryLobbyTaskID* pTaskID, CryMatchmakingCallback	cb, void* pCbArg );

	// Description:
	//	 Performs a search for sessions that match the specified search criteria.
	// Arguments:
	//	 user - The pad number of the user doing the search.
	//							In Live the TrueSkill system is used. Each session has a skill value worked out from the members skill values.
	//							The skill value of the user doing the search is used to return sessions that have skill values closest to the users value.
	//	 param - Pointer to a SCrySessionSearchParam that defines how sessions should be filtered
	//	 taskID - Pointer to buffer to store the task ID to identify this call in the callback
	//	 cb - Callback function that is called when function completes
	//	 pCbArg - Pointer to application-specified data that is passed to the callback
	// Return:
	//	 eCLE_Success if function successfully started or an error code if function failed to start
	virtual ECryLobbyError SessionSearch( uint32 user, SCrySessionSearchParam* pParam, CryLobbyTaskID* pTaskID, CryMatchmakingSessionSearchCallback cb, void* pCbArg );

	// Description:
	//	 Called to join a session previously created by a session host. Session
	//	 id's can be obtained from a session search or from a session invite
	//	 notification.
	// Arguments:
	//	 pUsers - Pointer to an array of pad numbers of the local users who will be joining the session
	//	 numUsers - Number of users in the users array
	//	 flags - Session create flags that control how the session behaves
	//	 id - A CrySessionID of the session that will be joined
	//	 pTaskID - Pointer to buffer to store the task ID to identify this call in the callback
	//	 cb - Callback function that is called when function completes
	//	 pCbArg - Pointer to application-specified data that is passed to the callback
	// Return:
	//	 eCLE_Success if function successfully started or an error code if
	//	 function failed to start.
	virtual ECryLobbyError SessionJoin( uint32* pUsers, int numUsers, uint32 flags, CrySessionID id, CryLobbyTaskID* pTaskID, CryMatchmakingSessionJoinCallback cb, void* pCbArg );

	// Description:
	//	 Set the local user data for the given user. This data gets sent around
	//	 the system and is returned for each user in a session with a call to
	//	 SessionGetUsers.
	// Arguments:
	//	 h - The handle of the session to set the user data for.
	//	 taskID - Pointer to buffer to store the task ID to identify this call in the callback
	//	 user - The pad number of the user whose data to set.
	//	 pData - The data you wish to set for the user.
	//	 dataSize - The size of the data max CRYLOBBY_USER_DATA_SIZE_IN_BYTES
	//	 cb - Callback function that is called when function completes
	//	 pCbArg - Pointer to application-specified data that is passed to the callback
	// Return:
	//	 Error code.
	virtual ECryLobbyError SessionSetLocalUserData( CrySessionHandle h, CryLobbyTaskID* pTaskID, uint32 user, uint8* pData, uint32 dataSize, CryMatchmakingCallback pCB, void* pCBArg );
	virtual	ECryLobbyError SessionSendRequestInfo(CCryLobbyPacket* pPacket, CrySessionID id, CryLobbyTaskID* pTaskID, CryMatchmakingSessionSendRequestInfoCallback pCB, void* pCBArg);
	virtual	ECryLobbyError SessionSendRequestInfoResponse(CCryLobbyPacket* pPacket, CrySessionRequesterID requester);

	virtual CrySessionID SessionGetCrySessionIDFromCrySessionHandle( CrySessionHandle h );

	virtual uint32 GetSessionIDSizeInPacket() const;

	virtual ECryLobbyError WriteSessionIDToPacket( CrySessionID sessionId, CCryLobbyPacket* pPacket ) const;

	virtual CrySessionID ReadSessionIDFromPacket( CCryLobbyPacket* pPacket ) const;

	virtual void Kick(const CryUserID* pUserID, EDisconnectionCause cause);

#if NETWORK_HOST_MIGRATION

	virtual bool GetNewHostAddress( char* pAddress, SHostMigrationInfo* pHostMigrationInfo );

	virtual void HostMigrationInitialise( CrySessionHandle h, EDisconnectionCause cause );
	virtual void HostMigrationFinalise(CrySessionHandle h);

	virtual ECryLobbyError HostMigrationServer( SHostMigrationInfo* pHostMigrationInfo );

#endif

	//////////////////////////////////////////////////////////

	virtual void OnGameSpyObjectAvailable( EGameSpyObjectBit object );
	virtual void OnGameSpyObjectUnavailable( EGameSpyObjectBit object );
	virtual void OnGameSpyObjectCantMakeAvailable( EGameSpyObjectBit object );

	virtual ECryLobbyError SessionEnsureBestHost( CrySessionHandle gh, CryLobbyTaskID* pTaskID, CryMatchmakingCallback pCB, void* pCBArg );
#if defined(DEDICATED_SERVER)
					ECryLobbyError SessionPropagatePassword(CrySessionHandle gh, CryLobbyTaskID* pTaskID, CryMatchmakingCallback pCB, void* pCBArg);
#endif // defined(DEDICATED_SERVER)
					void ProcessPropagatePassword(const TNetAddress& addr, CCrySharedLobbyPacket* pPacket);

	// Description:
	//	 Are we the host for the given session?
	// Arguments:
	//	 handle - session handle
	// Return:
	//	 true if we are the host.
	bool IsHost( CrySessionHandle handle );

	// Description:
	//	 List keys.
	// Arguments:
	//	 type - key type
	//	 keyBuffer - key buffer
	void ListKeys( qr2_key_type type, qr2_keybuffer_t keyBuffer );

	// Description:
	//	 Get a key.
	// Arguments:
	//	 type - key type
	//	 key - key index
	//	 index - player or team index (not for server keys)
	//	 buffer - return key value
	void QueryKey( qr2_key_type type, int key, int index, qr2_buffer_t buffer );

	bool GetServerKey( int key, size_t bufSize, char* pBuf );

	uint32 GetCurrentSessionPlayerCount();
	CrySessionHandle GetCurrentInvitableSessionHandle(void) const;

	void ClearTaskLinks();

	// Description:
	//	 Get a session ID from a session handle.
	// Arguments:
	//	 h - session handle
	// Return:
	//	 Session ID.
	virtual uint64 GetSIDFromSessionHandle( CrySessionHandle h );

	void AdjustSessionFriendCount( const char* pSessionURL, int32 delta );

	virtual CrySessionID GetSessionIDFromConsole();
	virtual ECryLobbyError GetSessionAddressFromSessionID( CrySessionID sessionID, uint32& hostIP, uint16& hostPort );
	virtual ECryLobbyError GetSessionIDFromSessionURL( const char* const pSessionURL, CrySessionID* const pSessionID );
	virtual ECryLobbyError GetSessionIDFromIP( const char* const pAddr, CrySessionID* const pSessionID );
	static void CreateChallengeString( char* pString );
	static ECryLobbyError TranslateCDKeyError( char* pErrMsg );

protected:

	enum ETask
	{
		eT_SessionRegisterUserData = eT_MatchMakingPlatformSpecificTask,
		eT_SessionCreate,
		eT_SessionMigrate,
		eT_SessionUpdate,
		eT_SessionUpdateSlots,
		eT_SessionQuery,
		eT_SessionGetUsers,
		eT_SessionStart,
		eT_SessionEnd,
		eT_SessionDelete,
		eT_SessionSearch,
		eT_SessionSearchWaitStart,
		eT_SessionJoin,
		eT_SessionJoinFindUseAddress,
		eT_SessionEnsureBestHost,
		eT_SessionSetLocalUserData,
		eT_SessionEnsureCorrectStagingRoom,
		eT_SessionSendRequestInfo,
		eT_SessionSendRequestInfoNAT,
		eT_InvalidTaskType,
#if defined(DEDICATED_SERVER)
		eT_SessionPropagatePassword,
#endif // defined(DEDICATED_SERVER)

		// ^^New task IDs *must* go before host migration tasks^^
		eT_SessionMigrateHostServer	= HOST_MIGRATION_TASK_ID_FLAG,
		eT_SessionMigrateHostClient,
		eT_SessionMigrateHostFinish
	};

	struct STask;

	enum ESessionPingState
	{
		eSPS_NotStarted,
		eSPS_SentPing,
		eSPS_GotPongValidSession,
		eSPS_ReportedToGame,
		eSPS_GotPongInvalidSession,
		eSPS_TimedOut
	};

	enum EGameMode
	{
		eGM_OpenWaiting,
		eGM_ClosedWaiting,
		eGM_ClosedPlaying,
		eGM_OpenPlaying,
		eGM_OpenStaging,
		eGM_ClosedStaging,
		eGM_Exiting,
		eGM_NumGameModes
	};

	enum ECDKeyChallengeState
	{
		eCDKCS_NotStarted,
		eCDKCS_AuthChallengeSent,
		eCDKCS_AuthValidationRequested,
		eCDKCS_ReauthChallengeSent,
		eCDKCS_ReauthResponseReceived,
		eCDKCS_ReauthValidationRequested,
		eCDKCS_ValidationSucceeded,
		eCDKCS_ValidationFailed
	};

	struct SSearch
	{
		struct SServer
		{
			SCrySessionSearchResult	result;
			uint32									createFlags;
			uint32									numMigrations;
			SBServer								server;
			ESessionPingState				sessionPingState;
			CTimeValue							firstPingSentTime;
			CTimeValue							lastPingSentTime;
			EGameMode								mode;
			bool										dedicated;
		};

		SServer									servers[ MAX_GAMESPY_SEARCH_SERVERS ];
		uint32									numServers;
		uint32									numExpectedServers;
		uint32									numServersAdded;
		bool										used;
		bool										finished;
	};

	struct	SRegisteredUserData
	{
		SCrySessionUserData		data[ MAX_MATCHMAKING_SESSION_USER_DATA] ;
		uint32								num;
	};

	// STaskLnks need to be in a list to prevent leaks when peerShutdown is
	// called with outstanding callbacks.

	struct STaskLink;

	typedef _smart_ptr<STaskLink> STaskLinkPtr;

	struct STaskLink: public CMultiThreadRefCount
	{
		void AddToVector( std::vector<STaskLinkPtr>& pVector )
		{
			m_pVector = &pVector;
			m_index = m_pVector->size();
			m_pVector->push_back( this );
		};

		void RemoveFromVector()
		{
			std::vector<STaskLinkPtr>*	pVector = m_pVector;
			SSIZE_T											index = m_index;

			( *pVector )[ pVector->size() - 1 ]->m_index = index;
			m_pVector = NULL;
			m_index = -1;
			( *pVector )[ index ] = ( *pVector )[ pVector->size() - 1 ]; // Don't dereference this after here!
			pVector->resize( pVector->size() - 1 );
		};

		STask*											pTask;
		CCryLobby*									pLobby;
		CCryGameSpyLobbyService*		pLobbyService;
		CCryGameSpyMatchMaking*			pMatchMaking;
		SSIZE_T											m_index;
		std::vector<STaskLinkPtr>*	m_pVector;
	};

	enum ESessionCreateTaskFlag
	{
		eSCTF_CreatedStagingRoom = BIT( 0 ),
		eSCTF_JoinedStagingRoom = BIT( 1 ),
		eSCTF_HavePublicAddress = BIT( 2 ),
		eSCTF_HaveLocalUserName = BIT( 3 ),
		eSCTF_DoneSetSessionData = BIT( 4 )
	};

	struct SSessionCreateParam
	{
		uint32								flags;
	};

	struct SSessionJoinParam
	{
		bool									finishedCryNetworkJoin;
	};

	enum EServerDataFlag
	{
		eSDF_Ranked = BIT( 0 ),
		eSDF_RequirePassword = BIT( 1 )
	};

	struct SSessionQueryParam
	{
		bool									started;
		bool									finished;
		bool									requirePassword;
	};

	struct STask: public CCryMatchMaking::STask
	{
		STaskLinkPtr					pLink;
		// GameSpy objects on which the task depends.
		uint8									oldGameSpyObjects;	// Required to be ready when task starts; starting task when they're not ready is an error. 
		uint8									newGameSpyObjects;	// Will be used; not an error to start task without them. Lobby service is notified that they're needed, possibly starting login.																												 
		uint8									haveGameSpyObjects;	// Objects ready at present.
		bool									searching;
	};

	struct SSession: public CCryMatchMaking::SSession
	{
		virtual const char* GetLocalUserName(uint32 localUserIndex) const;

		struct SLConnection: public CCryMatchMaking::SSession::SLConnection
		{
			char									name[ CRYLOBBY_USER_NAME_LENGTH] ;
			uint8									userData[ CRYLOBBY_USER_DATA_SIZE_IN_BYTES ];
			SCryGameSpyUserID			userID;
		};

		struct SRConnection: public CCryMatchMaking::SSession::SRConnection
		{
			char									name[ CRYLOBBY_USER_NAME_LENGTH ];
			uint8									userData[ CRYLOBBY_USER_DATA_SIZE_IN_BYTES ];
			SCryGameSpyRemoteConnectionID	id;
			GPProfile							m_profileID;
			CryMatchMakingTaskID	m_joinTaskID;
			ECDKeyChallengeState	m_cdKeyChallengeState;
			int32									m_cdKeyLocalID;
			int32									m_cdKeyReauthHint;
			char									m_cdKeyChallengeString[ GAMESPY_CD_KEY_CHALLENGE_SIZE ];
			bool									m_isDedicated;
#if NETWORK_HOST_MIGRATION
			bool								m_migrated;
#endif
		};

		std::map< uint8, string >	stringKeys;
		SCryGameSpySessionID	id;
		SLConnection					localConnection;
		SRConnection					remoteConnection[ MAX_LOBBY_CONNECTIONS ];
		SCrySessionUserData		userData[ MAX_MATCHMAKING_SESSION_USER_DATA ];
		SCrySessionData				data;
		uint16								numFilledSlots;
		uint16								specialFlags;
		uint32								numMigrations;
	};

#if NETWORK_HOST_MIGRATION

	enum EMigrateServerFlag
	{
		eMSF_FinishedCreate = BIT( 0 ),
		eMSF_SentPacket = BIT( 1 ),
		eMSF_StartedGame = BIT( 2 )
	};

	struct SMigrateServerParam
	{
		uint32								flags;
	};

	enum EMigrateClientFlag
	{
		eMCF_SentPacket = BIT( 0 )
	};

	struct SMigrateClientParam
	{
		CryMatchMakingTaskID	serverMmTaskId;
		uint32								flags;
	};

	void StartHostMigrationServer( CryMatchMakingTaskID mmTaskID );
	void TickHostMigrationServer( CryMatchMakingTaskID mmTaskID );
	void TickHostMigrationFinish( CryMatchMakingTaskID mmTaskID );
	static void HostMigrationServerPeerJoinRoomCallback( PEER peer, PEERBool success, PEERJoinResult result, RoomType roomType, void* pParam );
	void ProcessHostMigrationFromServer( const TNetAddress& addr, CCrySharedLobbyPacket* pPacket );
	void ProcessHostMigrationFromClient( const TNetAddress& addr, CCrySharedLobbyPacket* pPacket );
	void ProcessHostMigrationStart( const TNetAddress& addr, CCrySharedLobbyPacket* pPacket );
	void HostMigrationClient( SHostMigrationInfo* pHostMigrationInfo, CryMatchMakingTaskID serverMmTaskId );
	void StartHostMigrationClient( CryMatchMakingTaskID mmTaskID );
	void StartSessionEnsureBestHost( CryMatchMakingTaskID mmTaskID );

#endif

	enum EEnsureCorrectStagingRoomFlag
	{
		eECSRF_CheckedSearches = BIT( 0 ),
		eECSRF_FinishedSearch = BIT( 1 ),
		eECSRF_StartedJoin = BIT( 2 ),
		eECSRF_FinishedJoin = BIT( 3 ),
		eECSRF_StartedLeave = BIT( 4 ),
		eECSRF_FinishedLeave = BIT( 5 )
	};

	struct SEnsureCorrectStagingRoomParam
	{
		uint32								flags;
		SBServer							server;
	};

	//////////////////////////////////////////////////////////
	// Task management
	//////////////////////////////////////////////////////////

	// Description:
	//	 Create a task.
	// Arguments:
	//	 etask - task type
	//	 pMmTaskID - return matchmaking task ID
	//	 pLTaskID - return lobby task ID
	//	 h - session handle
	//	 cb - callback
	//	 pCbArg - callback argument
	// Return:
	//	 Error code.
	ECryLobbyError StartTask( ETask etask, CryMatchMakingTaskID* pMmTaskID, CryLobbyTaskID* pLTaskID, CrySessionHandle h, void* cb, void* pCbArg );

	// Description:
	//	 Start a task; must be called on network thread.
	// Arguments:
	//	 mmTaskID - matchmaking task ID
	void StartTaskRunning( CryMatchMakingTaskID	mmTaskID );

	// Description:
	//	 Stop a task; must be called on network thread.
	// Arguments:
	//	 mmTaskID - matchmaking task ID
	void StopTaskRunning( CryMatchMakingTaskID mmTaskID );

	// Description:
	//	 Handle task termination and invoke callback. Must be called on game thread.
	// Arguments:
	//	 mmTaskID - matchmaking task ID
	void EndTask( CryMatchMakingTaskID	mmTaskID );

	// Description:
	//	 Clear a task.
	// Arguments:
	//	 mmTaskID - matchmaking task ID
	void ClearTask( CryMatchMakingTaskID mmTaskID );

	bool CreateTaskLink( CryMatchMakingTaskID mmTaskID );
	static void FreeTaskLinkFromCryNetwork( STask* pTask );
	static void FreeTaskLinkFromGameSpy( STaskLink* pLink );
	void InitializeTaskGameSpyObjects( STask* pTask, uint8 newObjects, uint8 oldObjects );
	ETaskGameSpyCheckResult CheckTaskGameSpyObjects( CryMatchMakingTaskID mmTaskID );

	//////////////////////////////////////////////////////////
	// Session create task
	//////////////////////////////////////////////////////////

	// Description:
	//	 Start a session create task.
	// Arguments:
	//	 mmTaskID - matchmaking task ID
	void StartSessionCreate( CryMatchMakingTaskID	mmTaskID );

	// Description:
	//	 Tick a session create task.
	// Arguments:
	//	 mmTaskID - matchmaking task ID
	void TickSessionCreate( CryMatchMakingTaskID mmTaskID );

	// Description:
	//	 End a session create task.
	// Arguments:
	//	 mmTaskID - matchmaking task ID
	void EndSessionCreate( CryMatchMakingTaskID mmTaskID );

	//////////////////////////////////////////////////////////
	// Session join task
	//////////////////////////////////////////////////////////

	// Description:
	//	 Start a session join task.
	// Arguments:
	//	 mmTaskID - matchmaking task ID
	void StartSessionJoin( CryMatchMakingTaskID mmTaskID );
	void TickSessionJoin( CryMatchMakingTaskID mmTaskID );
	uint32 CreateNATCookie(SCryGameSpyRemoteConnectionID* pAddr);
	void StartFindUseAddress(SCryGameSpyRemoteConnectionID* pAddr, uint32 cookie, int clientIndex, bool serverJoin);
	void TickSessionJoinFindUseAddress(CryMatchMakingTaskID mmTaskID);
	void StartSessionRequestJoin( CryMatchMakingTaskID mmTaskID );
	static void NATNegotiateProgressCallback(NegotiateState state, void* pUserData);
	static void NATNegotiateCompletedCallback(NegotiateResult result, SOCKET gamesocket, struct sockaddr_in *pRemoteAddr, void *pUserData);
	static bool CompleteNATNegotiation( NegotiateResult nnResult, CCryLobby* pLobby, uint32 cookie, SCryGameSpyRemoteConnectionID* pAddr, SSession::SRConnection* pConnection, struct sockaddr_in* pRemoteAddr );

	//////////////////////////////////////////////////////////
	// Session search task
	//////////////////////////////////////////////////////////

	// Description:
	//	 Start a session search task.
	// Arguments:
	//	 mmTaskID - matchmaking task ID
	void StartSessionSearch( CryMatchMakingTaskID mmTaskID );

	// Description:
	//	 Tick a session search task.
	// Arguments:
	//	 mmTaskID - matchmaking task ID
	void TickSessionSearch( CryMatchMakingTaskID mmTaskID );
	void TickSessionSearchWaitStart(CryMatchMakingTaskID mmTaskID);
	void FormatSearchTerm( const char* pLogic, const SCrySessionSearchData* pData, CryFixedStringT< GAMESPY_SEARCH_FILTER_AVAILABLE_LEN >& filter );

	// Description:
	//	 End a session search task.
	// Arguments:
	//	 mmTaskID - matchmaking task ID
	void EndSessionSearch( CryMatchMakingTaskID mmTaskID );

	// Description:
	//	 Return a session search result.
	// Arguments:
	//	 cb - callback
	//	 taskID - lobby task ID
	//	 error - error
	//	 pResult - result
	//	 pCbArg - callback argument
	void ReturnSessionSearch( CryMatchmakingSessionSearchCallback cb, CryLobbyTaskID taskID, ECryLobbyError error, SCrySessionSearchResult* pResult, void* pCbArg );

	// Description:
	//	 Called when state of session search changes.
	// Arguments:
	//	 peer - PEER
	//	 success - was the search successful?
	//	 pName - name of game
	//	 server - server
	//	 staging - true if not yet in gameplay
	//	 msg - type of update
	//	 progress - percentage of servers added
	//	 pParam - user data
	static void SessionSearchPeerListingGamesCallback( PEER peer, PEERBool success, const gsi_char* pName, SBServer server, PEERBool staging, int msg, int progress, void* pParam );

	static void ReadInternalKeyFromSBServer( uint8 key, SSearch::SServer* pServer, SBServer sbServer );

	static void ReadUserKeyFromSBServer( uint8 key, uint8 keyUserDataIdx, ECryLobbyUserDataType type, SSearch::SServer* pServer, SBServer server );

	static bool FilterKey( SCryLobbyUserData* pSessionData, SCrySessionSearchData* pSearchData );

#if GAMESPY_ENABLE_SESSION_PING
	void ProcessSessionPing( const TNetAddress& addr, CCrySharedLobbyPacket* pPacket );

	void ProcessSessionPong( const TNetAddress& addr, CCrySharedLobbyPacket* pPacket );
#endif

	void SendCDKeyChallenge( SSession::SRConnection* pConnection, char* pChallenge );
	void ProcessCDKeyChallenge( const TNetAddress& addr, CCrySharedLobbyPacket* pPacket );
	void ProcessCDKeyResponse( const TNetAddress& addr, CCrySharedLobbyPacket* pPacket );
	static void CDKeyAuthCallback( int gameid, int localid, int authenticated, char* pErrMsg, void* pParam );
	static void CDKeyReauthCallback( int gameid, int localid, int hint, char* pChallenge, void* pParam );

	//////////////////////////////////////////////////////////
	// Session delete task
	//////////////////////////////////////////////////////////

	// Description:
	//	 Start a session delete task.
	// Arguments:
	//	 mmTaskID - match making task ID
	void StartSessionDelete( CryMatchMakingTaskID mmTaskID );

	//////////////////////////////////////////////////////////
	// Session get users task
	//////////////////////////////////////////////////////////

	// Description:
	//	 End a SessionGetUsers task.
	// Arguments:
	//	 mmTaskID - match making task ID
	void EndSessionGetUsers( CryMatchMakingTaskID mmTaskID );

	//////////////////////////////////////////////////////////
	// Session set local user data task
	//////////////////////////////////////////////////////////

	// Description:
	//	 Start a session set local user data task.
	// Arguments:
	//	 mmTaskID - matchmaking task ID.
	void StartSessionSetLocalUserData( CryMatchMakingTaskID mmTaskID );

	// Description:
	//	 Process a local user data packet.
	// Arguments:
	//	 addr - sender
	//	 pPacket - packet
	void ProcessLocalUserData( const TNetAddress& addr, CCrySharedLobbyPacket* pPacket );

	//////////////////////////////////////////////////////////
	// Session update task
	//////////////////////////////////////////////////////////

	// Description:
	//	 Start a session update task.
	// Arguments:
	//	 mmTaskID - matchmaking task ID.
	void StartSessionUpdate( CryMatchMakingTaskID mmTaskID );
	void TickSessionUpdate( CryMatchMakingTaskID mmTaskID );

	// Description:
	//	 Push user data to GameSpy.
	// Arguments:
	//	 localSessionIndex - local session index
	void PushUserData( CrySessionHandle localSessionIndex );

	// Description:
	//	 Pull user data from GameSpy.
	// Arguments:
	//	 localSessionIndex - local session index
	void PullUserData( CrySessionHandle localSessionIndex );

	//////////////////////////////////////////////////////////
	// Session query task
	//////////////////////////////////////////////////////////

	// Description:
	//	 Start a session query task.
	// Arguments:
	//	 mmTaskID - matchmaking task ID.
	void StartSessionQuery( CryMatchMakingTaskID mmTaskID );

	// Description:
	//	 Tick a session create task.
	// Arguments:
	//	 mmTaskID - matchmaking task ID
	void TickSessionQuery( CryMatchMakingTaskID mmTaskID );

	void EndSessionQuery( CryMatchMakingTaskID mmTaskID );

	void SendServerData( const TNetAddress& addr, CCrySharedLobbyPacket* pPacket );
	void ProcessServerData( const TNetAddress& addr, CCrySharedLobbyPacket* pPacket );
	uint32 CalculateServerDataSize(CrySessionHandle h);

	void StartSessionStart( CryMatchMakingTaskID mmTaskID );
	void TickSessionStart( CryMatchMakingTaskID mmTaskID );
	void StartSessionEnd( CryMatchMakingTaskID mmTaskID );
	void TickSessionEnd( CryMatchMakingTaskID mmTaskID );

	void EnsureCorrectStagingRoom();
	void SessionEnsureCorrectStagingRoom( CrySessionHandle localSessionIndex );
	void StartSessionEnsureCorrectStagingRoom( CryMatchMakingTaskID mmTaskID );
	void TickSessionEnsureCorrectStagingRoom( CryMatchMakingTaskID mmTaskID );
	static void SessionEnsureCorrectStagingRoomPeerJoinRoomCallback( PEER peer, PEERBool success, PEERJoinResult result, RoomType roomType, void* pParam );
	static void SessionEnsureCorrectStagingRoomPeerLeaveRoomCallback( void* pParam );
	static void SessionEnsureCorrectStagingRoomPeerListingGamesCallback( PEER peer, PEERBool success, const gsi_char* pName, SBServer server, PEERBool staging, int msg, int progress, void* pParam );

	void	StartSessionSendRequestInfo(CryMatchMakingTaskID mmTaskID);
	void	TickSessionSendRequestInfo(CryMatchMakingTaskID mmTaskID);
	void	TickSessionSendRequestInfoNAT(CryMatchMakingTaskID mmTaskID);
	void	EndSessionSendRequestInfo(CryMatchMakingTaskID mmTaskID);
	void	DispatchSessionRequestInfo(CrySessionHandle gh, TMemHdl packetMH, uint32 length, TMemHdl requesterMH);
	void	ProcessSessionRequestInfo(const TNetAddress& addr, CCrySharedLobbyPacket* pPacket);
	void	SessionSendRequestInfoResponseNT(TMemHdl packetMH, uint32 length, TMemHdl requesterMH);
	void	ProcessSessionRequestInfoResponse(const TNetAddress& addr, CCrySharedLobbyPacket* pPacket);

#if defined(DEDICATED_SERVER)
	void	StartSessionPropagatePassword(CryMatchMakingTaskID mmTaskID);
#endif // defined(DEDICATED_SERVER)

	//////////////////////////////////////////////////////////
	// Handle management
	//////////////////////////////////////////////////////////

	// Description:
	//	 Create a session handle.
	// Arguments:
	//	 pLocalSessionIndex - return session handle
	//	 host - is local machine host?
	//	 createFlags - flags
	//	 numUsers - number of local users
	// Return:
	//	 Error code
	ECryLobbyError CreateSessionHandle( CrySessionHandle* pLocalSessionIndex, bool host, uint32 createFlags, int numUsers );

	// Description:
	//	 Create a session search handle.
	// Arguments:
	//	 pSearchHandle - return session handle
	// Return:
	//	 Error code
	ECryLobbyError CreateSessionSearchHandle( CrySessionHandle* pSearchHandle );

	// Description:
	//	 Create a session ID.
	// Return:
	//	 The session ID.
	uint64 CreateSessionID();

	SCryGameSpyRemoteConnectionID CreateRemoteConnectionID( uint32 useIP, uint16 usePort, uint32 publicIP, uint16 publicPort, uint32 privateIP, uint16 privatePort );

	CryLobbyConnectionID GetLobbyConnectionFromRemoteConnectionID( SCryGameSpyRemoteConnectionID& remoteConnectionID );

	CrySessionHandle FindSessionFromSessionID( uint64 sessionID );

	// Description:
	//	 Set session data.
	// Arguments:
	//	 localSessionIndex - session handle
	//	 pData - session data
	// Return:
	//	 Error code.
	ECryLobbyError SetSessionData( CrySessionHandle localSessionIndex, SCrySessionData* pData );

	// Description:
	//	 Set session user data.
	// Arguments:
	//	 localSessionIndex - session handle
	//	 pData - session user data
	//	 numData - user data count
	// Return:
	//	 Error code.
	ECryLobbyError SetSessionUserData( CrySessionHandle localSessionIndex, SCrySessionUserData* pData, uint32 numData );

	CCryGameSpyLobbyService*	GetService();
	
	// Description:
	//	 Called when a peerCreateStagingRoom completes.
	// Arguments:
	//	 peer - PEER
	//	 success - was the peerCreateStagingRoom successful?
	//	 result - type of result
	//	 roomType - always StagingRoom for this callback
	//	 pParam - pointer to STaskLink
	static void SessionCreatePeerJoinRoomCallback( PEER peer, PEERBool success, PEERJoinResult result, RoomType roomType, void* pParam );

	// Description:
	//	 Session user data event.
	// Arguments:
	//	 event - event
	//	 localSessionIndex - session handle
	//	 id - connection ID
	void SessionUserDataEvent( ECryLobbySystemEvent event, CrySessionHandle localSessionIndex, CryMatchMakingConnectionID id );

	// Description:
	//	 Initial session user data events.
	// Arguments:
	//	 localSessionIndex - session handle
	void InitialUserDataEvent( CrySessionHandle localSessionIndex );

	// Description:
	//	 Process a join request packet.
	// Arguments:
	//	 addr - sender
	//	 pPacket - packet
	void ProcessSessionRequestJoin( const TNetAddress& addr, CCrySharedLobbyPacket*	pPacket );

	void SessionJoinFail( uint64 sessionID, ECryLobbyError error, CryMatchMakingTaskID returnTaskID, const TNetAddress& addr );

	ECryLobbyError SessionJoinSuccess( SSession* pSession, CryMatchMakingConnectionID id, CryMatchMakingTaskID returnTaskID, CrySessionHandle localSessionIndex );
	// Description:
	//	 Process an add remote connections packet.
	// Arguments:
	//	 addr - sender
	//	 pPacket - packet
	void ProcessSessionAddRemoteConnections( const TNetAddress& addr, CCrySharedLobbyPacket* pPacket );

	// Description:
	//	 Process a join request result packet.
	// Arguments:
	//	 addr - sender
	//	 pPacket - packet
	void ProcessSessionRequestJoinResult( const TNetAddress& addr, CCrySharedLobbyPacket* pPacket );

	CryMatchMakingConnectionID	AddRemoteConnection( CrySessionHandle h, CryLobbyConnectionID connectionID, SCryMatchMakingConnectionUID uid, uint32 useIP, uint16 usePort, uint32 publicIP, uint16 publicPort, uint32 privateIP, uint16 privatePort, uint32 numUsers, const char* pName, uint8 userData[ CRYLOBBY_USER_DATA_SIZE_IN_BYTES ], bool isDedicated );
	virtual void FreeRemoteConnection( CrySessionHandle h, CryMatchMakingConnectionID id );

	// IP addresses and ports.
	uint32 GetPublicIP();
	uint16 GetPublicPort();
	uint32 GetPrivateIP();
	uint16 GetPrivatePort();

	static void ClearSessionSearch( SSearch* pSearch );
	static void FreeSessionSearch( SSearch* pSearch );
	static void ClearSessionSearchServer( SSearch::SServer* pServer );
	static void FreeSessionSearchServer( SSearch::SServer* pServer );
	static void MoveSessionSearchServer( SSearch::SServer* pDstServer, SSearch::SServer* pSrcServer );
	ECryLobbyError StartTaskSearching( CryMatchMakingTaskID mmTaskID, const unsigned char* pFields, int numFields, const gsi_char* pFilter, peerListingGamesCallback callback, void* pParam );
	void StopTaskSearching( CryMatchMakingTaskID mmTaskID );
	void InvalidateSessionSearchSBServers( SSearch* pSearch );

	void ResetTask(CryMatchMakingTaskID mmTaskID);

	virtual const char*	GetConnectionName(CCryMatchMaking::SSession::SRConnection* pConnection, uint32 localUserIndex) const;
	virtual uint64 GetConnectionUserID(CCryMatchMaking::SSession::SRConnection* pConnection, uint32 localUserIndex) const;
	virtual void BanCmd(uint64 userID, float timeout);
	virtual void UnbanCmd(uint64 userID);
	virtual void BanStatus(void);
	virtual void Ban(const CryUserID* pUserID, float timeout);

	void InformVoiceRemoteUsersJoined(CrySessionHandle h, CryMatchMakingConnectionID id);
	void InformVoiceRemoteUsersLeft(CrySessionHandle h, CryMatchMakingConnectionID id);

	void DispatchRoomOwnerChangedEvent(TMemHdl mh);

	void CreateSessionURL( uint32 ip, uint16 port, uint64 sid, CryFixedStringT< GAMESPY_MAX_SESSION_URL_SIZE >& url );

	static void EncodeU8( uint8 val, char* pStr );
	static void EncodeU16( uint16 val, char* pStr );
	static void EncodeU32( uint32 val, char* pStr );
	static void EncodeU64( uint64 val, char* pStr );
	static void DecodeU8( uint8& val, const char* pStr );
	static void DecodeU16( uint16& val, const char* pStr );
	static void DecodeU32( uint32& val, const char* pStr );
	static void DecodeU64( uint64& val, const char* pStr );
	static void EncodeS8( int8 val, char* pStr );
	static void EncodeS16( int16 val, char* pStr );
	static void EncodeS32( int32 val, char* pStr );
	static void EncodeS64( int64 val, char* pStr );
	static void DecodeS8( int8& val, const char* pStr );
	static void DecodeS16( int16& val, const char* pStr );
	static void DecodeS32( int32& val, const char* pStr );
	static void DecodeS64( int64& val, const char* pStr );
	static void EncodeU( uint64 val, char* pStr, uint64 divisor );

	// Registered user data.
	SRegisteredUserData				m_registeredUserData;

	// Session searches.
	SSearch										m_search[ MAX_GAMESPY_SEARCHES ];

	// Sessions.
	SSession									m_sessions[ MAX_MATCHMAKING_SESSIONS ];

	// Tasks.
	STask											m_task[ MAX_MATCHMAKING_TASKS ];

	// Task links.
	std::vector<STaskLinkPtr>	m_taskLinks;

	uint32										m_cdKeyLocalIDCycle;

	// GameSpy keys.
	uint8											m_keyUserDataIdx[ MAX_REGISTERED_KEYS ];
	uint8											m_numServerReportKeys;
	uint8											m_serverReportKeys[ MAX_REGISTERED_KEYS ];
	uint8											m_numServerQueryUserDataKeys;
	uint8											m_serverQueryUserDataKeys[ MAX_REGISTERED_KEYS ];
	uint8											m_numServerSearchQueryKeys;
	uint8											m_serverSearchQueryKeys[ MAX_REGISTERED_KEYS ];
	uint8											m_numServerSearchReportKeys;
	uint8											m_serverSearchReportKeys[ MAX_REGISTERED_KEYS ];
	uint8											m_numPlayerKeys;
	uint8											m_playerKeys[ MAX_REGISTERED_KEYS ];
	uint8											m_numTeamKeys;
	uint8											m_teamKeys[ MAX_REGISTERED_KEYS ];
	uint8											m_numericKeyToStringKey[ MAX_REGISTERED_KEYS ];
	uint8											m_stringKeyToNumericKey[ MAX_REGISTERED_KEYS ];

	static const char* const	k_gameModeNames[ eGM_NumGameModes ];

	// Names of CryNetwork reserved GameSpy keys.
	static const char* const	k_sessionIDKeyName;
	static const char* const	k_numPrivateSlotsKeyName;
	static const char* const	k_numPublicSlotsKeyName;
	static const char* const	k_rankedKeyName;
	static const char* const	k_createFlagsKeyName;
	static const char* const	k_numMigrationsKeyName;
	static const char* const	k_passwordRequiredKeyName;
	static const char* const	k_dedicatedKeyName;

	static const char					k_encodeNumericKey[ GAMESPY_ENCODE_NUMERIC_TABLE_SIZE ];
	static const int8					k_decodeNumericKey[ GAMESPY_DECODE_NUMERIC_TABLE_SIZE ];
};


#endif // USE_CRYLOBBY_GAMESPY


#endif // __CRYGAMESPYMATCHMAKING_H__
